package Util;
import java.util.Hashtable;
import java.util.LinkedList;

import Data.Automata;
import Data.FinalVariables;
import Data.GrammarRule;
import Data.Relation;
import Data.State;
import static Data.FinalVariables.*;

public class GrammarConverter {
	public Hashtable <String, State> stateList;
	public LinkedList <String> stateNames;
	public LinkedList <Relation> relationList = new LinkedList <Relation> ();
	public GrammarConverter(){
		this.stateList=new Hashtable <String, State> ();
		this.stateNames=new LinkedList <String>();
	}
	private void createStates(LinkedList <GrammarRule> rulesToConvert){
		for(int i=0; i<rulesToConvert.size();i++){
				int x = (int) (Math.random()*455);
				int y = (int) (Math.random()*420);
				
				this.stateList.put(rulesToConvert.get(i).substitutionName,new State(rulesToConvert.get(i).substitutionName,x,y));
				this.stateNames.add(rulesToConvert.get(i).substitutionName);
				System.out.println(rulesToConvert.get(i).substitutionName+""+rulesToConvert.get(i).getSubstitutionValue());
				if(rulesToConvert.get(i).getSubstitutionValue().length()==1&&Character.isLowerCase(rulesToConvert.get(i).getSubstitutionValue().charAt(0))&&!this.stateList.containsKey("Z")&&rulesToConvert.get(i).getSubstitutionValue().charAt(0)!='e'){
					 x = (int) (Math.random()*455);
					 y = (int) (Math.random()*420);
					
						 System.out.println("Created z");
							State zstate = new State("Z",x,y);
							zstate.setStateType(FINAL_STATE);
							this.stateList.put("Z",zstate);
							this.stateNames.add("Z");
				
				}
		}
		
		
	}
	public void GrammarToAutomata(LinkedList <GrammarRule> rulesToConvert){
		this.createStates(rulesToConvert);
		
		for(int i=0; i<rulesToConvert.size(); i++){
			/*
			 * Two cases, when the rule is substituted by a final symbol or epsilon and
			 * when the rule is substituted for a final symbol and another rule
			 */
			GrammarRule tempRule = rulesToConvert.get(i);
			State tempState = this.stateList.get(tempRule.substitutionName);
			if(tempRule.getSubstitutionName().equalsIgnoreCase("S")&&Character.isLowerCase(tempRule.getSubstitutionValue().charAt(0))){
				
				if(tempRule.getSubstitutionValue().charAt(0)=='e'){
					tempState.setStateType(INITIAL_FINAL);
					State sourceState = this.stateList.get(tempRule.substitutionName);
					sourceState.setStateType(INITIAL_FINAL);
				}
				else {
					if(!(tempState.getStateType()==INITIAL_FINAL)){
						tempState.setStateType(INITIAL_STATE);
					}
					
					if(tempRule.getSubstitutionValue().length()>1){
						State sourceState = this.stateList.get(tempRule.substitutionName);
						State finalState = this.stateList.get(tempRule.substitutionValue.charAt(1)+"");
						String transitionValue = tempRule.substitutionValue.charAt(0)+"";
						relationList.add(new Relation(sourceState, finalState, transitionValue));
					}
					else {
						State sourceState = this.stateList.get(tempRule.substitutionName);
						State finalState = this.stateList.get("Z");
						String transitionValue = tempRule.substitutionValue.charAt(0)+"";
						relationList.add(new Relation(sourceState, finalState, transitionValue));
					}
				
				}
			
			
			}
			else{
			if((tempRule.getSubstitutionValue().length()==1&&(Character.isLowerCase(tempRule.getSubstitutionValue().charAt(0))))||tempRule.getSubstitutionName().equalsIgnoreCase("Z")){
				System.out.println("Single rule: "+tempRule.toString());
				 if(tempRule.getSubstitutionValue().equalsIgnoreCase("e")){
						tempState.setStateType(FINAL_STATE);
						System.out.println("EPSILON");
					}
				else{
					System.out.println("ENTER!!! WITH"+tempRule.getSubstitutionName()+tempRule.getSubstitutionValue());
					State sourceState = this.stateList.get(tempRule.substitutionName);
					State finalState = this.stateList.get("Z");
					String transitionValue = tempRule.substitutionValue.charAt(0)+"";
					relationList.add(new Relation(sourceState, finalState, transitionValue));
				}
				 
				 if(!(tempState.getStateType()==FINAL_STATE)||tempState.getStateType()==INITIAL_STATE){
						tempState.setStateType(NORMAL_STATE);
					}
			}
			
			else{
				State sourceState = this.stateList.get(tempRule.substitutionName);
				State finalState = this.stateList.get(tempRule.substitutionValue.charAt(1)+"");
				String transitionValue = tempRule.substitutionValue.charAt(0)+"";
				relationList.add(new Relation(sourceState, finalState, transitionValue));
				
			}
					
			}
		}
	}
	
	public String convertFromAutomata(Automata automata){
		LinkedList <State> epsilonStates= new LinkedList<State>();
		StringBuilder grammarBuilder = new StringBuilder();
		for(int i = 0; i<automata.getRelations().size(); i++){
			Relation temp = automata.getRelations().get(i);
			State sourceState = temp.getSourceState();
			State destState = temp.getDestinationState();
			if((sourceState.getStateType()==FINAL_STATE||sourceState.getStateType()==INITIAL_FINAL)&&!this.isStateAdded(sourceState,epsilonStates)){
				epsilonStates.add(sourceState);
			}
			if((destState.getStateType()==FINAL_STATE||destState.getStateType()==INITIAL_FINAL)&&!this.isStateAdded(destState,epsilonStates)){
				epsilonStates.add(destState);
			}
			String rule = sourceState.getStateName()+"-"+temp.getTransitionValue()+destState.getStateName();
			grammarBuilder.append(rule+"\n");
		}
		for(int i=0; i<epsilonStates.size(); i++){
			grammarBuilder.append(epsilonStates.get(i).getStateName()+"-e\n");
		}
		System.out.println(grammarBuilder.toString());
		
		return grammarBuilder.toString();
	}
	
	public boolean isStateAdded(State state, LinkedList<State> toSearch){
		for(int i=0; i<toSearch.size(); i++){
			State temp = toSearch.get(i);
			if(temp.getStateName().equalsIgnoreCase(state.getStateName())){
				return true;
			}
		}
		return false;
	}
}
